// Copyright (c) 2023, 2024, Oracle and/or its affiliates.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 2.0,
// as published by the Free Software Foundation.
//
// This program is designed to work with certain software (including
// but not limited to OpenSSL) that is licensed under separate terms,
// as designated in a particular file or component or in included license
// documentation.  The authors of MySQL hereby grant you an additional
// permission to link the program and your derivative works with the
// separately licensed software that they have either included with
// the program or referenced in the documentation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License, version 2.0, for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.

#ifndef GR_CERTIFICATION_GTID_GENERATOR_INCLUDED
#define GR_CERTIFICATION_GTID_GENERATOR_INCLUDED

#include <unordered_map>

#include "plugin/group_replication/include/certification/gtid_generator_for_sidno.h"
#include "plugin/group_replication/include/certification_result.h"
#include "sql/rpl_gtid.h"

namespace gr {

/// @brief This class is responsible for generating GTIDs in the Certifier
/// @details Gtid certifier uses one instance of this class for generation of
/// GTIDs.
/// Gtid generator keeps track of free GTIDs for specific sidnos for each
/// GR member. To achieve that, it consults gtid_set provided.
/// When gtid generation is requested, GTID generator
/// will reserve for each member a block
/// of free GTIDS of size provided during the initialization
/// (gtid_assignment_block_size). Recalculation of GTID blocks may be requested
/// by the call to the "reset" function. New GTID may be generated by the call
/// to the "get_next_available_gtid" function.
/// Access to Gtid_generator must be synchronized by the user.
class Gtid_generator {
 public:
  /// @brief This method is used to get the next valid GNO for the given sidno,
  /// for the transaction originating from the group member identified by
  /// the 'member_uuid'.
  /// This method may consult gtid_set for the list of available GTIDs
  /// @param member_uuid        The UUID of the member from which this
  ///                           transaction originates. It will be NULL
  ///                           on View_change_log_event.
  /// @param sidno              The sidno that will be used on GTID
  /// @param gtid_set           Gtid set under consideration
  /// @returns A pair of:
  ///  - Generated gno and OK in case gno generation was possible
  ///  - invalid gno and ERROR:
  ///   (-1) when there are no available gnos for this SIDNO
  ///   (-2) when assigned GTIDs block is exhausted
  std::pair<rpl_gno, mysql::utils::Return_status> get_next_available_gtid(
      const char *member_uuid, rpl_sidno sidno, const Gtid_set &gtid_set);

  /// @brief This function recomputes generator state
  /// @param gtid_set           Gtid set under consideration
  void recompute(const Gtid_set &gtid_set);

  /// @brief This is initialization function that will be called in the
  ///        certifier
  /// @param gtid_assignment_block_size This is the size of gtid assignment
  /// block
  void initialize(uint64 gtid_assignment_block_size);

  /// @brief Accesses gtid assignment block size the Gtid_generator was
  /// initialized with
  /// @return Gtid assignment block size
  auto get_gtid_assignment_block_size() const {
    return m_gtid_assignment_block_size;
  }

 private:
  /// GTID bookkeeping for each sidno
  std::unordered_map<rpl_sidno, Gtid_generator_for_sidno>
      m_gtid_generator_for_sidno;

  /// The group GTID assignment block size.
  uint64 m_gtid_assignment_block_size = 1;
};

}  // namespace gr

#endif  // GR_CERTIFICATION_GTID_GENERATOR_INCLUDED
